/**
*	@class Image
*
*	@brief This class will be responsible for storing image data that can be used by textures etc.
*
*	@author William McVicar
*/

#pragma once

#ifndef __IMAGE_H_INCLUDED__
#define __IMAGE_H_INCLUDED__

//  Library Includes

//  Local Includes

//  Macros

//  Forward Declarations

//  Types
typedef enum
{
	PF_UNKNOWN,

	PF_RGB8,
	PF_RGBA8,
	PF_BGR8,
	PF_BGRA8,
	PF_ABGR8,
	PF_ALPHA8,
	PF_INTENSITY8,
	PF_LUMINANCE8,
	PF_LUMINANCEALPHA8,
	PF_RGB565,
	PF_RGBA5551,
	PF_ARGB1555,
	PF_RGBA4444,
	PF_ARGB4444,
	PF_DXT1,
	PF_DXT3,
	PF_DXT5,

	PF_MAX

} ePixelFormat;

typedef enum
{
	IF_BMP,
	IF_DDS,
	IF_TGA,
	IF_UNSUPPORTED
} eImageFormat;

//  Constants

//  Prototypes

namespace Protein
{

class Image
{
friend class CDDS;
friend class CBMP;
friend class CTGA;
	//Member Functions
public:

	Image();
	~Image();

	inline u32 Width() const;
	inline u32 Height() const;
	inline u32 Depth() const;
	inline u32 Width( i32 mipMapLevel ) const;
	inline u32 Height( i32 mipMapLevel ) const;
	inline u32 Depth( i32 mipMapLevel ) const;

	inline u32 MipMapCount() const;
	inline ePixelFormat PixelFormat() const;
	inline byte* Data() const;
	inline u32 dataSize() const;

	inline bool isCompressedFormat( ePixelFormat _format ) const;
	inline i32 getBytesPerBlock( ePixelFormat _format ) const;
	inline i32 getBytesPerPixel( ePixelFormat _format ) const;

	inline void getNextMipmapSize( u32& width, u32& height, u32& depth);
	u32 getImageDataSize(u32 width, u32 height, u32 depth, ePixelFormat pixelFormat );

	i32 GetMipMappedSize(const i32 firstMipMapLevel, i32 nMipMapLevels ) const;

	bool load( const char* szFilename );
	void clear();

protected: 

private: 

	void Init( u32 _width, 
			   u32 _height, 
			   u32 _depth, 
			   ePixelFormat _format, 
			   u32 _mipMapCount, 
			   const std::string& path,
			   byte* _data,
			   u32 _datasize );

	//Member Variables
public:

	u32				m_uiDataSize;

protected: 

private: 

	u32				m_uiWidth;
	u32				m_uiHeight;
	u32				m_uiDepth;
	u32				m_uiMipMapCount;

	ePixelFormat	m_ePixelFormat;

	std::string		m_imagePath;

	byte*	m_pData;

	static i32		sm_bytesPerPixel[ PF_MAX ];
};

inline u32 Image::Width() const
{
	return m_uiWidth;
}

inline u32 Image::Height() const
{
	return m_uiHeight;
}

inline u32 Image::Depth() const
{
	return m_uiDepth;
}

inline u32 Image::Width( i32 mipMapLevel) const 
{
	i32 a = m_uiWidth >> mipMapLevel;
	return (a == 0)? 1 : a;
}

inline u32 Image::Height( i32 mipMapLevel) const 
{
	i32 a = m_uiHeight >> mipMapLevel;
	return (a == 0)? 1 : a;
}

inline u32 Image::Depth( i32 mipMapLevel) const 
{
	i32 a = m_uiDepth >> mipMapLevel;
	return (a == 0)? 1 : a;
}

inline u32 Image::MipMapCount() const
{
	return m_uiMipMapCount;
}

inline ePixelFormat Image::PixelFormat() const
{
	return m_ePixelFormat;
}

inline byte* Image::Data() const
{
	return m_pData;
}

inline u32 Image::dataSize() const
{
	return m_uiDataSize;
}

inline bool Image::isCompressedFormat( ePixelFormat _format ) const
{
	return ( _format >= PF_DXT1 );
}

inline i32 Image::getBytesPerBlock( ePixelFormat _format ) const
{
	return ( _format == PF_DXT1 ) ? 8 : 16;
}

inline void Image::getNextMipmapSize( u32& width, u32& height, u32& depth)
{
	width  >>= 1;
	height >>= 1;
	depth  >>= 1;

	if( width < 1U )
		width = 1U;

	if( height < 1U )
		height = 1U;

	if( depth < 1U )
		depth = 1U;
}

inline i32 Image::getBytesPerPixel( ePixelFormat _format ) const
{
	static const i32 bytesPP[] = {
		0,		//PF_UNKNOWN
		3,		//PF_RGB8
		4,		//PF_RGBA8
		3,		//PF_BGR8
		4,      //PF_BGRA8
		4,		//PF_ABGR8
		1,		//PF_ALPHA8
		1,		//PF_INTENSITY8
		1,		//PF_LUMINANCE8
		2,		//PF_LUMINANCEALPHA8
		2,		//PF_RGB565
		2,		//PF_RGBA5551
		2,      //PF_ARGB1555
		2,		//PF_RGBA4444
		2,		//PF_ARGB4444
		3,		//PF_DXT1
		4,      //PF_DXT2
		4,		//PF_DXT3
		0
	};
	return bytesPP[_format];
}

}

#endif //__IMAGE_H_INCLUDED__
